<?php

namespace App\Http\Controllers\Api;

use App\Common\Libs\Ali\AliYunSms;
use App\Common\Libs\Ali\OssClient;
use App\Events\TestEvent;
use App\Http\Controllers\BaseController;
use App\Jobs\TestCastJob;
use App\Models\Cache\Redis;
use App\Models\Config;
use App\Models\SysArticle;
use App\Models\User;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

/**
 * Class TestController
 * [!] 为了测试方便，所有逻辑都写在了 Controller 层
 * [!] 正常开发，逻辑应写到 Service 层。
 * @package App\Http\Controllers\Api
 */
class TestController extends BaseController
{

    /**
     * 普通缓存使用示例
     * Cache 是根据 .env CACHE_DRIVER 而定
     * 主要包含： file,memcached,redis,dynamodb,database,array,apc 等缓存方式
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function cache(Request $request)
    {
        $params = $request->all();

        $cacheKey = 'z_test_cache';
        Cache::put($cacheKey, '123-'.time());

        $data = ['cache' => Cache::get($cacheKey)];

        return $this->apiReturn($data);
    }

    /**
     * redis 使用示例
     * 单独的 Redis 实列，与 Cache 明确区分
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function redis(Request $request)
    {
        $params = $request->all();

        $cacheKey = 'z_test_redis';
        Redis::set($cacheKey, '1234-'.time());

        $data = ['redis' => Redis::get($cacheKey)];

        return $this->apiReturn($data);
    }

    /**
     * 队列使用示例
     * 基于 Redis，可更改 .env QUEUE_CONNECTION 而改变
     * [!] 生产环境配置为 mns，非生产环境配置成 redis
     * [!] 代码无需改变，调用方式不变
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function queue(Request $request)
    {
        $params = $request->all();

        Log::channel('job')->info('enter api : ' . json_encode($params));
        // 入队列进行异步处理
        TestCastJob::dispatch($params)->delay(1);
        TestCastJob::dispatch(['scene' => 'job_test_2'])->delay(5);

        $data = ['job' => true];

        return $this->apiReturn($data);
    }

    /**
     * 事件使用示例
     * [!] 可在 EventServiceProvider 定义监听器
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function event(Request $request)
    {
        $params = $request->all();

        Log::channel('event')->info('enter api : ' . json_encode($params));
        // 分发事件
        TestEvent::dispatch([
            'scene' => 'event_test_3',
            'params' => $params,
            'time' => time(),
        ]);

        $data = ['event' => true];

        return $this->apiReturn($data);
    }

    /**
     * http 使用示例
     * 基于 GuzzleHttp
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function http(Request $request)
    {
        $params = $request->all();

        try{
            $client = new Client([
                'base_uri'        => 'http://192.168.150.128:9092',
                'timeout'         => 3,
                // cookies 可以不携带
                'cookies'         => CookieJar::fromArray(['PHPSESSID' => 'b68212de1826c64d77b69dc514c2a9cb'], 'http://192.168.150.128:9092'),
            ]);
            $res = $client->get('/api/article/index', ['query' => ['params' => 'true','test' => 12345]]);
            $list = [
                'code' => $res->getStatusCode(),
                'headers' => json_encode($res->getHeaders()),
                'content' => $res->getBody()->getContents(),
                'meta' => json_encode($res->getBody()->getMetadata()),
            ];
        } catch (GuzzleException $e) {
            $list = [
                'code' => $e->getCode(),
                'headers' => $e->getPrevious(),
                'content' => $e->getMessage(),
                'meta' => $e->getFile().':'.$e->getLine(),
            ];
        }

        $data = ['http' => $list];

        return $this->apiReturn($data);
    }

    /**
     * 本地下载文件使用示例
     * 基于 GuzzleHttp
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function download(Request $request)
    {
        $params = $request->all();

        $url = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1606210200795&di=f687c6384705c50adea623ce2be69b65&imgtype=0&src=http%3A%2F%2Fa4.att.hudong.com%2F27%2F67%2F01300000921826141299672233506.jpg';
        // 节省本地空间，用原URL进行md5加密，正常开发每次分配随机ID
        $path = '/public/test-'.md5($url).'.jpg';
        try {
            // 绕过 SSL 验证
            $client = new Client(['verify' => false]);
            $res = $client->get($url, [
                'save_to' => storage_path('app').$path
            ]);
            $content = $res->getBody()->getContents();
            $list = [
                'code' => $res->getStatusCode(),
                'headers' => json_encode($res->getHeaders()),
                'content' => base64_encode($content),
                'meta' => json_encode($res->getBody()->getMetadata()),
            ];
            // 确保文件一定被写入
            if (!file_exists(storage_path('app').$path)) {
                Storage::disk('local')->put($path, $content);
            }
        } catch (GuzzleException $e) {
            $list = [
                'code' => $e->getCode(),
                'headers' => $e->getPrevious(),
                'content' => $e->getMessage(),
                'meta' => $e->getFile().':'.$e->getLine(),
            ];
        }

        $data = [
            'path' => env('APP_URL') . $path,
            'origin' => $url,
            'list' => $list
        ];

        return $this->apiReturn($data);
    }

    /**
     * 本地上传文件使用示例
     * [!] 此方法为 POST ，因请求参数 test_logo 为 file 类型
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function upload(Request $request)
    {
        $params = $request->all();

        // 获取文件类型参数
        $file = $request->file('test_logo');
        if (empty($file) || !$file->isValid()) {
            return $this->apiReturn('file is invalid!',999);
        }

        $originName = $file->getClientOriginalName();
        $ext = $file->getClientOriginalExtension();
        $path = $file->getRealPath();
        // 节省本地空间，用原名进行md5加密，正常开发每次分配随机ID
        $fileName = "/public/test-".md5($originName).".$ext";
        // 写入文件到本地
        Storage::disk('local')->put($fileName, file_get_contents($path));

        $data = [
            'path' => env('APP_URL') . $fileName,
            'tmp_file' => $path,
            'origin_name' => $originName,
        ];

        return $this->apiReturn($data);
    }

    /**
     * OSS 使用示例
     * [!] 此方法为 POST ，因请求参数 test_oss_file 为 file 类型
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function oss(Request $request)
    {
        $params = $request->all();

        // 获取文件类型参数
        $file = $request->file('test_oss_file');
        if (empty($file) || !$file->isValid()) {
            return $this->apiReturn('file is invalid!',999);
        }

        $originName = $file->getClientOriginalName();
        $ext = $file->getClientOriginalExtension();
        $path = $file->getRealPath();
        // 不用节省空间，每次请求生成唯一ID
        $fileName = "lv8/test-".uniqid().".$ext";

        // 上传文件到 OSS
        $result = OssClient::getInstance()->putObject($fileName, $path);

        $data = [
            'oss' => $result,
            'tmp_file' => $path,
            'origin_name' => $originName,
        ];

        return $this->apiReturn($data);
    }

    /**
     * ES 使用示例
     * [!] 搜索规则在 elasticsearch.conf 中配置
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function es(Request $request)
    {
        $params = $request->all();
        $keyWord = $params['key_word'] ?? '';

        // 使用 ES 进行搜索
        $data = [
            // 使用中文分词检索用户表
            'user_index' => User::search($keyWord)->get()->take(2),
            // 使用拼音分词检索信息表
            'info_index' => Config::search($keyWord)->orderBy('id', 'desc')->get()->take(10),
            // 分表情况进行检索文章表
            'sys_article_index' => SysArticle::search($keyWord)->take(2),
        ];

        return $this->apiReturn($data);
    }

    /**
     * 发送短信示例
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function sms(Request $request)
    {
        $params = $request->all();

        // 发送短信
        $phone = $params['php'] ?? '15757117946';
        $tpl = $params['sms_template'] ?? '1';
        $code =  mt_rand(100000, 999999);
        $data = AliYunSms::getInstance()->send($phone, $tpl, $code);

        return $this->apiReturn($data);
    }

}
